멤버 초대 모달 추가#35
Conversation
Summary of ChangesHello @Jieunsse, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 PR은 두 가지 새로운 모달 컴포넌트, 즉 멤버 초대 모달과 할 일 목록 추가 모달을 도입합니다. 이 모달들은 각각의 기능과 UI/UX를 제공하며, 기존 Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
이 PR은 멤버 초대와 할 일 목록 추가를 위한 두 가지 새로운 모달 컴포넌트를 도입합니다. 코드 리뷰 결과, 몇 가지 중요한 수정이 필요한 사항이 발견되었습니다.
가장 시급한 문제로, AddTodoList 모달에서 사용자가 입력한 값을 처리하는 로직이 누락되어 기능이 동작하지 않습니다. 또한, 두 모달 모두에서 커스텀 스타일을 적용하기 위해 사용된 contentClassName prop이 실제 Modal 컴포넌트에서 처리되지 않아 디자인이 깨지는 문제가 있습니다.
그 외에도 CSS에서 불필요한 선택자 중복, 고정 높이 값 사용, 그리고 React 컴포넌트 내 하드코딩된 ID 사용 등 유지보수성과 안정성을 개선할 수 있는 부분들이 있습니다. 자세한 내용은 각 파일에 남긴 리뷰 코멘트를 참고해주세요.
I am having trouble creating individual review comments. Click here to see my feedback.
src/components/Modal/domain/AddTodoList.tsx (12-16)
onCreate prop의 타입이 () => void로 되어 있어, 사용자가 입력한 할 일 목록의 이름을 전달할 수 없습니다. (name: string) => void로 수정하여 입력값을 전달받을 수 있도록 해야 합니다.
export interface AddTodoListProps {
isOpen: boolean;
onClose: () => void;
onCreate: (name: string) => void;
}
src/components/Modal/domain/AddTodoList.tsx (18-52)
현재 AddTodoList 컴포넌트는 Input의 값을 상위 컴포넌트로 전달하는 로직이 구현되어 있지 않습니다. useState를 사용하여 입력 값을 제어하고, form 제출 시 onCreate 콜백으로 전달하도록 수정해야 합니다.
(참고: useState를 사용하려면 import { useState } from 'react'; 구문이 필요합니다.)
export default function AddTodoList({ isOpen, onClose, onCreate }: AddTodoListProps) {
const [name, setName] = useState('');
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!name.trim()) {
return; // 이름이 비어있으면 생성하지 않음
}
onCreate(name);
setName(''); // 생성 후 입력 필드 초기화
};
const handleClose = () => {
setName(''); // 모달을 닫을 때 입력 필드 초기화
onClose();
};
return (
<Modal
isOpen={isOpen}
onClose={handleClose}
ariaLabelledby={TITLE_ID}
contentClassName={styles.modalContent}
>
<article className={styles.container}>
<header className={styles.header}>
<h2 id={TITLE_ID} className={styles.title}>
할 일 목록
</h2>
<button type="button" className={styles.closeButton} aria-label="close" onClick={handleClose}>
<Image src={xMarkBig} alt="" width={24} height={24} />
</button>
</header>
<form className={styles.form} onSubmit={handleSubmit}>
<Input
className={styles.input}
placeholder="할 일을 입력하세요"
value={name}
onChange={(e) => setName(e.target.value)}
autoFocus
/>
<footer className={styles.footer}>
<button type="submit" className={styles.button} disabled={!name.trim()}>
만들기
</button>
</footer>
</form>
</article>
</Modal>
);
}
src/components/Modal/domain/AddTodoList.tsx (29)
contentClassName prop을 Modal 컴포넌트에 전달하고 있지만, Modal.tsx 구현에서 이 prop을 사용하고 있지 않아 스타일이 적용되지 않습니다. 이로 인해 AddTodoList와 MemberInvite 모달의 border-radius 등 주요 스타일이 누락됩니다.
Modal.tsx 파일을 수정하여 contentClassName을 div의 className에 추가해야 합니다.
// Modal.tsx
export default function Modal({
// ...,
contentClassName,
}: ModalProps) {
// ...
return (
// ...
<div
className={clsx(style.contentsBox, contentClassName)}
// ...
>
{children}
</div>
// ...
);
}src/components/Modal/domain/AddTodoList.module.css (41-49)
.input.input 선택자는 불필요하게 중복되었습니다. .input으로 수정해도 동일하게 동작하며, 코드가 더 명확해집니다. 이는 의도치 않은 동작을 방지하고 가독성을 높입니다.
.input {
padding: 14px 16px;
width: 100%;
max-width: var(--input-max-width);
height: var(--control-height);
box-sizing: border-box;
align-self: center;
text-align: center;
}
src/components/Modal/domain/AddTodoList.module.css (98-102)
.modalContent.modalContent 선택자는 불필요하게 중복되었습니다. .modalContent로 수정해도 동일하게 동작하며, 코드가 더 명확해집니다.
.modalContent {
--dialog-radius-desktop: 24px;
--dialog-radius-mobile: 24px 24px 0 0;
border-radius: var(--dialog-radius-desktop);
}
src/components/Modal/domain/MemberInvite.module.css (5-7)
.container에 고정된 height 값을 사용하면 내용이 변경될 때 레이아웃이 깨질 수 있습니다. 예를 들어, 텍스트가 길어지면 컨테이너 밖으로 넘칠 수 있습니다. height 속성을 제거하고 내부 콘텐츠와 padding에 의해 높이가 자연스럽게 결정되도록 하는 것이 더 유연하고 안정적인 방법입니다. 84행의 height도 함께 제거하는 것을 권장합니다.
width: 384px;
padding: 40px 24px 32px;
src/components/Modal/domain/MemberInvite.tsx (15-48)
ariaLabelledby와 ariaDescribedby에 하드코딩된 문자열 ID를 사용하고 있습니다. 만약 이 컴포넌트가 한 페이지에 여러 번 렌더링될 경우 ID 충돌이 발생할 수 있습니다. React 18의 useId 훅을 사용하면 고유한 ID를 생성하여 이 문제를 해결할 수 있습니다.
(참고: useId를 사용하려면 import { useId } from 'react'; 구문이 필요합니다.)
export default function MemberInvite({ isOpen, onClose, inviteLink, onCopy }: MemberInviteProps) {
const titleId = useId();
const descId = useId();
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(inviteLink);
} finally {
onCopy?.(inviteLink);
}
};
return (
<Modal
isOpen={isOpen}
onClose={onClose}
ariaLabelledby={titleId}
ariaDescribedby={descId}
contentClassName={styles.modalContent}
>
<div className={styles.container}>
<button type="button" className={styles.closeButton} onClick={onClose} aria-label="close">
<Image src={xMarkBig} alt="" width={24} height={24} />
</button>
<h2 id={titleId} className={styles.title}>
멤버 초대
</h2>
<p id={descId} className={styles.description}>
그룹에 참여할 수 있는 링크를 복사합니다.
</p>
<button type="button" className={styles.copyButton} onClick={handleCopy}>
링크 복사하기
</button>
</div>
</Modal>
);
}
Summary
Issue
이슈번호 #33
Scope